#ifndef METHOD_H
#define METHOD_H

#include "Problem.h"
#include <RandomLib/Random.hpp>

typedef std::vector<std::vector<double> > matrix;
using namespace RandomLib;

struct OptimizedValue
{
    double value;
    std::vector<double> atPoint;
};

class Method
{
public:
    enum SubType
    {
        DEClassical
    };
    static Method * createMethod(SubType subType=DEClassical, Problem * problem=NULL, unsigned int popSize=100, unsigned int iterations=100);

    Method(const SubType & subType=DEClassical, Problem * problem=NULL, unsigned int popSize=100, unsigned int iterations=100);
    ~Method();

    void initialize();
    virtual OptimizedValue optimize(int caseProblem)=0;

    void printMethod();

    std::string getName()
    {
        return name;
    }
    int getPopulationSize()
    {
        return populationSize;
    }
    void setPopulationSize(int val)
    {
        populationSize = val;
    }
    unsigned int getIterations()
    {
        return iterations;
    }
    void setIterations(unsigned int val)
    {
        iterations = val;
    }
    Problem * getProblem()
    {
        return problem;
    }

protected:
    void printPopulation(const matrix & population)const;
    void printVector(const std::vector<double> & v)const;

    std::vector<double> cost;
    matrix parentPopulation;
    matrix mutatedPopulation;
    matrix crossoverPopulation;
    unsigned int bestFittedIndex;
    RandomLib::Random r;
    int populationSize;

private:
    Method();
    Method(const Method& other);
    Method& operator=(const Method& other);

    void initializeCost();

    SubType mSubType;
    std::string name;
    Problem * problem;
    unsigned int iterations;
};

#endif // METHOD_H

